/*
 * Copyright Aristool AG Switzerland
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 */
package org.opprua.tidy.beans;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import org.opprua.tidy.conversion.ChangerBroker;

/**
 * TODO: add Java doc
 * 
 * Prepared for first commit: 15.07.2007
 * 
 * @author Lin Li
 */
class BeanCoupler {

  private static Map<String, BeanCoupler> molds = Collections
              .synchronizedMap(new TreeMap<String, BeanCoupler>());

  private static class Pair {

    String name = null;
    BeanField source = null;
    BeanField target = null;
  }

  private Pair[] pairs = null;

  private BeanCoupler() {
  }

  public static synchronized BeanCoupler getFor(Class<?> sourceType, Class<?> targetType) {
    String key = sourceType.getName() + " " + targetType.getName();
    BeanCoupler h = (BeanCoupler) molds.get(key);
    if (h == null) {
      h = new BeanCoupler();
      h.harmonize(sourceType, targetType);
      molds.put(key, h);
    }
    return h;
  }

  private void harmonize(Class<?> sourceType, Class<?> targetType) {
    Set<String> names = new TreeSet<String>();

    Map<String, BeanField> osource = BeanField.getFields(sourceType);
    Map<String, BeanField> otarget = BeanField.getFields(targetType);

    names.addAll(osource.keySet());
    names.retainAll(otarget.keySet());

    List<Pair> p = new ArrayList<Pair>();
    for (Iterator<String> iter = names.iterator(); iter.hasNext();) {
      Pair pair = new Pair();
      pair.name = iter.next();
      pair.source = (BeanField) osource.get(pair.name);
      pair.target = (BeanField) otarget.get(pair.name);
      p.add(pair);
    }
    pairs = (Pair[]) p.toArray(new Pair[0]);
  }

  public int copy(Object source, Object target) {
    int c = pairs.length;
    for (int i = 0; i < pairs.length; i++) {
      Object s = pairs[i].source.get(source);
      boolean success = false;
      try {
        pairs[i].target.set(target, s);
        success = true;
      } catch (Throwable t) {}
      if (success) {
        continue;
      }
      try {
        pairs[i].target.set(target, ChangerBroker.convert(pairs[i].target.getType(), s));
        success = true;
      } catch (Throwable t) {}
      if (success) {
        continue;
      }

      c--;
    }
    return c;
  }
}